package com.alibaba.citrus.cr.price.ability.functions.factory.price;

import com.alibaba.citrus.cr.price.ability.functions.entity.price.PriceDimensionConfigEntity;
import com.alibaba.citrus.cr.price.ability.functions.entity.price.PriceEntity;
import com.alibaba.citrus.cr.price.ability.functions.entity.price.PriceRecordEntity;
import com.alibaba.citrus.cr.price.ability.functions.entity.price.PriceTypeEntity;
import com.alibaba.citrus.cr.price.ability.functions.entity.price.QueryPriceProcessLog;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.util.DateUtils;
import com.alibaba.citrus.cr.price.ability.functions.entity.price.*;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.epoch.app.crpricecenter.dto.request.DimensionPropertyInfoRequest;
import com.epoch.app.crpricecenter.dto.request.MaterialInfoRequest;
import com.epoch.app.crpricecenter.dto.request.PriceQueryRequest;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;

import java.util.*;

/**
 * @author: qiaojiange
 * @create: 2021/09/15
 * @Description 价格工厂
 */
public class PriceFactory {
    /**
     * 最大查询个数
     */
    private static int MAX_ITEM_COUNT_PER_QUERY = 2000;
    /**
     * 日志
     */
    public static Log log = Log.getLogger(PriceFactory.class);
    /**
     * 查询价格日志
     */
    static String QUERY_PRICE_LOG = "queryPriceLog";

    /**
     * 创建价格
     *
     * @param request
     * @return
     */
    public static List<PriceEntity> createPrice(PriceQueryRequest request) {
        //检验入参
        checkPriceQueryRequest(request);

        //批量获取
        List<PriceEntity> result = new ArrayList<>();
        for (DimensionPropertyInfoRequest e : request.getDimensionPropertyInfoRequestList()) {

            PriceEntity priceEntity = new PriceEntity();

            //设置标签
            priceEntity.setQueryFlag(e.getQueryFlag());

            priceEntity.setItemId(obtainItemId(e.getMaterialInfoRequest()));
            PriceTypeEntity priceTypeEntity = PriceTypeFactory.create(e.getPriceTypeId());
            priceEntity.setPriceTypeEntity(priceTypeEntity);

            //获取维度配置实体map
            Map<String, PriceDimensionConfigEntity> priceDimensionConfigEntityMap =
                    PriceDimensionConfigFactory.createDimensionConfigEntityMap(priceTypeEntity, e);

            //计数器
            Integer[] countArray = new Integer[1];
            countArray[0] = 1;

            Map<String, String> queryResultMap = Maps.newHashMap();
            List<QueryPriceProcessLog> processLogList = new ArrayList<>();
            //未查询到数据时，不直接抛异常，而是存入标签到结果里
            if (MapUtils.isEmpty(priceDimensionConfigEntityMap)) {
                buildLogAndAdd(processLogList, countArray, "价格查询失败: 获取维度id和配置数据的映射表为空,请检查维度属性配置表ofs_price_property_config是否存在对应的数据!");
                queryResultMap.put(QUERY_PRICE_LOG, JSON.toJSONString(processLogList, SerializerFeature.WriteDateUseDateFormat));
                priceEntity.setFeatures(queryResultMap);
                result.add(priceEntity);
                continue;
            }

            //获取维度顺序，获取维度顺序中存在的一个维度中的价格数据。 这里是真正的匹配过程！！！
            List<String> sequence = priceTypeEntity.obtainDimensionSequence();
            for (String str : sequence) {
                PriceDimensionConfigEntity dimensionConfigEntity = priceDimensionConfigEntityMap.get(str);
                if (Objects.nonNull(dimensionConfigEntity) && StringUtils.isNotBlank(dimensionConfigEntity.obtainRecodeId())) {
                    if (dimensionConfigEntity.isCanUse(e.getPriceUseDate())) {
                        //判断价格记录是否存在，如果不存在继续遍历其他的维度
                        PriceRecordEntity priceRecord = PriceRecordFactory.create(dimensionConfigEntity.obtainRecodeId());
                        if (Objects.isNull(priceRecord.getPriceRecordSDO())) {
                            log.info("当前维度数据价格记录号在价格记录表中不存在,请检查ofs_price_record表是否存在该价格记录号,price_record_id：" +
                                    dimensionConfigEntity.obtainRecodeId());
                            buildLogAndAdd(processLogList, countArray, "价格查询失败：当前维度匹配成功，但无对应的价格记录，" +
                                    "请检查ofs_price_record表是否存在该价格记录号,price_record_id："
                                    + dimensionConfigEntity.obtainRecodeId());
                            continue;
                        }
                        priceEntity.setRecordEntity(priceRecord);
                        priceEntity.setDimensionConfigEntity(dimensionConfigEntity);
                        //追加维度信息到features里面
                        queryResultMap.put("dimensionId", str);
                        log.info("该维度匹配,{},{}", str, dimensionConfigEntity);
                        buildLogAndAdd(processLogList, countArray, "价格查询成功：" + str + "维度匹配成功!" + " md5编码" + dimensionConfigEntity.obtainMd5Code());
                        break;
                    } else {
                        //维度匹配但时间不在价格的时间范围内时
                        log.info("该价格不可用，因为当前时间不在价格可用时间范围内", str, dimensionConfigEntity);
                        StringBuilder sb = new StringBuilder().append("该").append(str).append("维度价格不可用，原因当前时间：")
                                .append(DateUtils.formatDate(e.getPriceUseDate(), "yyyy-MM-dd HH:mm:ss"))
                                .append("不在价格可用时间范围内，时间范围(开始时间：")
                                .append(DateUtils.formatDate(dimensionConfigEntity.obtainPriceStartDate(), "yyyy-MM-dd HH:mm:ss"))
                                .append("结束时间：")
                                .append(DateUtils.formatDate(dimensionConfigEntity.obtainPriceEndDate(), "yyyy-MM-dd HH:mm:ss"))
                                .append(")")
                                .append(" md5编码:")
                                .append(dimensionConfigEntity.obtainMd5Code());
                        buildLogAndAdd(processLogList, countArray, sb.toString());
                    }
                }

                if (Objects.isNull(dimensionConfigEntity)) {
                    log.info("当前维度" + str + "不匹配!", dimensionConfigEntity);
                    buildLogAndAdd(processLogList, countArray, "该维度不匹配:" + str);
                }
                if (Objects.nonNull(dimensionConfigEntity) && StringUtils.isBlank(dimensionConfigEntity.obtainRecodeId())) {
                    log.info("未获取到价格记录数据", dimensionConfigEntity);
                    buildLogAndAdd(processLogList, countArray, "未获取到价格记录数据！");
                }
            }

            //检验价格数据
            //CheckUtils.checkNotNull(priceEntity.getDimensionConfigEntity(), "OTS-07-006-01-16-001",null);
            //未查询到数据时，不直接抛异常，而是存入标签到结果里
            if (Objects.isNull(priceEntity.getDimensionConfigEntity())) {
                buildLogAndAdd(processLogList, countArray, "价格查询失败：当前所有维度均匹配完成，还是未查到该商品的价格！");
                processLogList.stream().sorted((o1, o2) -> {
                    return o1.getCount() <= o2.getCount() ? 1 : -1;
                });
                //升序排列
                ascSortProcessLog(processLogList);
                queryResultMap.put(QUERY_PRICE_LOG, JSON.toJSONString(processLogList, SerializerFeature.WriteDateUseDateFormat));
                priceEntity.setFeatures(queryResultMap);
                result.add(priceEntity);
                continue;
            }

            //升序排列
            ascSortProcessLog(processLogList);
            queryResultMap.put(QUERY_PRICE_LOG, JSON.toJSONString(processLogList, SerializerFeature.WriteDateUseDateFormat));

            //设置价格类型
            queryResultMap.put("priceType",priceEntity.obtainPriceType());

            priceEntity.setFeatures(queryResultMap);
            result.add(priceEntity);
        }
        return result;
    }

    /**
     * 升序排列处理日志
     * @param processLogList
     */
    private static void ascSortProcessLog(List<QueryPriceProcessLog> processLogList) {
        if (CollectionUtils.isEmpty(processLogList)) {
            return;
        }
        Collections.sort(processLogList, (o1, o2) -> {
            return o1.getCount() >= o2.getCount() ? 1 : -1;
        });

    }


    /**
     * 构造价格的处理日志，同时添加到列表中
     *
     * @param list       存储日志列表
     * @param countArray 计数器
     * @param msg        信息
     */
    private static void buildLogAndAdd(List<QueryPriceProcessLog> list, Integer[] countArray, String msg) {
        if (StringUtils.isBlank(msg)) {
            return;
        }
        if (list == null) {
            list = new ArrayList<>();
        }

        QueryPriceProcessLog log = new QueryPriceProcessLog();
        log.setCount(countArray[0]++);
        log.setProcessDesc(msg);
        list.add(log);
        return;
    }

    /**
     * 校验价格查询请求
     *
     * @param request
     */
    private static void checkPriceQueryRequest(PriceQueryRequest request) {

        if (Objects.isNull(request)) {
            throw new FacadeException("查询价格入参不能为空！");
        }

        if (CollectionUtils.isNotEmpty(request.getDimensionPropertyInfoRequestList())) {
            if (request.getDimensionPropertyInfoRequestList().size() > MAX_ITEM_COUNT_PER_QUERY) {
                throw new FacadeException("单次查询价格的货品数量大于" + MAX_ITEM_COUNT_PER_QUERY + "个，请分批查询！", request);
            }
        }

    }

    private static String obtainItemId(MaterialInfoRequest materialInfoRequest) {
        return materialInfoRequest == null ? "" : materialInfoRequest.getMaterialCode();
    }

}
